﻿using Microsoft.Win32;
using OpenLibSys;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO.Ports;
using System.Text;
using System.Text.RegularExpressions;

namespace WindowService
{
    public class IOHelper
    {
        SerialPort serialPort = null;
        Ols ols = null;

        public IOHelper()
        {
            initGpio();
        }

        private void initGpio()
        {
            //-----------------------------------------------------------------------------
            // Initialize
            //-----------------------------------------------------------------------------
            ols = new Ols();

            // Check support library sutatus
            switch (ols.GetStatus())
            {
                case (uint)Ols.Status.NO_ERROR:
                    break;
                case (uint)Ols.Status.DLL_NOT_FOUND:
                    Log.WriteLog("IOHelper Check WinRing0 Status Error!! DLL_NOT_FOUND", LogType.Error);
                    return;
                    
                case (uint)Ols.Status.DLL_INCORRECT_VERSION:
                    Log.WriteLog("IOHelper Check WinRing0 Status Error!! DLL_INCORRECT_VERSION", LogType.Error);
                    return;
                    
                case (uint)Ols.Status.DLL_INITIALIZE_ERROR:
                    Log.WriteLog("IOHelper Check WinRing0 Status Error!! DLL_INITIALIZE_ERROR", LogType.Error);
                    return;
                    
            }

            // Check WinRing0 status
            switch (ols.GetDllStatus())
            {
                case (uint)Ols.OlsDllStatus.OLS_DLL_NO_ERROR:
                    break;
                case (uint)Ols.OlsDllStatus.OLS_DLL_DRIVER_NOT_LOADED:
                    Log.WriteLog("IOHelper Check WinRing0 DLL Status Error!! OLS_DRIVER_NOT_LOADED", LogType.Error);
                    return;
                    
                case (uint)Ols.OlsDllStatus.OLS_DLL_UNSUPPORTED_PLATFORM:
                    Log.WriteLog("IOHelper Check WinRing0 DLL Status Error!! OLS_UNSUPPORTED_PLATFORM", LogType.Error);
                    return;
                    
                case (uint)Ols.OlsDllStatus.OLS_DLL_DRIVER_NOT_FOUND:
                    Log.WriteLog("IOHelper Check WinRing0 DLL Status Error!! OLS_DLL_DRIVER_NOT_FOUND", LogType.Error);
                    return;
                    
                case (uint)Ols.OlsDllStatus.OLS_DLL_DRIVER_UNLOADED:
                    Log.WriteLog("IOHelper Check WinRing0 DLL Status Error!! OLS_DLL_DRIVER_UNLOADED", LogType.Error);
                    return;
                    
                case (uint)Ols.OlsDllStatus.OLS_DLL_DRIVER_NOT_LOADED_ON_NETWORK:
                    Log.WriteLog("IOHelper Check WinRing0 DLL Status Error!! DRIVER_NOT_LOADED_ON_NETWORK", LogType.Error);
                    return;
                    
                case (uint)Ols.OlsDllStatus.OLS_DLL_UNKNOWN_ERROR:
                    Log.WriteLog("IOHelper Check WinRing0 DLL Status Error!! OLS_DLL_UNKNOWN_ERROR", LogType.Error);
                    return;
                    
            }
        }

        //检测COM口状态
        public string checkCom(string portName, string holdingType)
        {
            Log.WriteLog("IOHelper Check SerialPort", LogType.Trace);
            serialPort = new SerialPort();
            try {
                serialPort.PortName = portName;
                    serialPort.DtrEnable = true;
                    serialPort.RtsEnable = true;
                if (!serialPort.IsOpen)
                {
                    serialPort.Open();
                }
                switch (holdingType)
                {
                    case "8":
                        Log.WriteLog("IOHelper Check SerialPort PortName:" + portName + " serialPort.CtsHolding:" + serialPort.CtsHolding.ToString(), LogType.Trace);
                        return serialPort.CtsHolding ? "1" : "0";
                    case "4":
                        Log.WriteLog("IOHelper Check SerialPort PortName:" + portName + " serialPort.DsrHolding:" + serialPort.DsrHolding.ToString(), LogType.Trace);
                        return serialPort.DsrHolding ? "1" : "0";
                    case "1":
                        Log.WriteLog("IOHelper Check SerialPort PortName:" + portName + " serialPort.CDHolding:" + serialPort.CDHolding.ToString(), LogType.Trace);
                        return serialPort.CDHolding ? "1" : "0";
                }

                Log.WriteLog("IOHelper Config " + portName + " holding type " + holdingType + " error, must in ('8', '4', '1')", LogType.Error);
            }
            catch (Exception e)
            {
                Log.WriteLog("IOHelper Read " + portName + " holding type " + holdingType + " error:" + e.Message, LogType.Error);
            }
            finally
            {
                if (serialPort.IsOpen)
                {
                    serialPort.Close();
                }
            }

            return "0";
        }
        //检测GPIO状态
        public string checkGpio(string portName, string bitNumber)
        {
            Log.WriteLog("IOHelper Check GPIO", LogType.Trace);
            try
            {
                int portNameInt = Convert.ToInt32(portName, 16);
                int bitNumberInt = Convert.ToInt32(Math.Pow(2, Convert.ToInt32(bitNumber)));
                int portValue = ols.ReadIoPortByte((ushort)portNameInt);
                Log.WriteLog("IOHelper Check GPIO PortName:" + portName + " bitNumber:" + bitNumber + " value:" + portValue, LogType.Trace);
                return (portValue & bitNumberInt) == bitNumberInt ? "1" : "0";
            }
            catch (Exception e)
            {
                Log.WriteLog("IOHelper Read GPIO " + portName + " " + bitNumber + " error:" + e.Message, LogType.Error);
            }
            return "0";
        }


        private const string ComKey1 = @"HARDWARE\DEVICEMAP\SERIALCOMM";
        private const string ComKey2 = @"SYSTEM\CurrentControlSet\Control\DeviceClasses\{86e0d1e0-8089-11d0-9ce4-08003e301f73}";
        private const string ComKey3 = @"SYSTEM\CurrentControlSet\Enum";

        public List<SerialPortEnumInfo> GetCommInfoList()
        {
            Log.WriteLog("IOHelper Getting SerialPort List", LogType.Trace);
            List<SerialPortEnumInfo> commInfoList = new List<SerialPortEnumInfo>();
            List<SerialPortEnumInfo> tempComm = new List<SerialPortEnumInfo>();
            try
            {
                using (RegistryKey myKey = Registry.LocalMachine.OpenSubKey(ComKey1))
                {
                    Log.WriteLog("IOHelper Registry OpenSubKey Key:[" + Registry.LocalMachine.ToString() + "\\" + ComKey1 + "]", LogType.Trace);
                    if (myKey == null)
                    {
                        Log.WriteLog("IOHelper Registry SubKey:[" + Registry.LocalMachine.ToString() + "\\" + ComKey1 + "] is not exist", LogType.Error);
                        return tempComm;
                    }
                    foreach (string valueName in myKey.GetValueNames())
                    {
                        string value = myKey.GetValue(valueName).ToString();
                        Log.WriteLog("IOHelper Registry GetValue Key:[" + Registry.LocalMachine.ToString() + "\\" + ComKey1 + "] " + valueName.ToString() + ":\"" + value.ToString() + "\"", LogType.Trace);
                        if (string.IsNullOrEmpty(valueName) || string.IsNullOrEmpty(value))
                        {
                            continue;
                        }
                        SerialPortEnumInfo commInfo = new SerialPortEnumInfo();
                        commInfo.path = valueName;
                        commInfo.name = value;
                        if (!isNumber(value.ToUpper().Replace("COM", "")))
                        {
                            continue;
                        }
                        commInfo.num = Convert.ToInt32(value.ToUpper().Replace("COM", ""));
                        tempComm.Add(commInfo);
                    }
                }

                if (tempComm.Count <= 0)
                {
                    return tempComm;
                }
                using (RegistryKey myKey2 = Registry.LocalMachine.OpenSubKey(ComKey2))
                {
                    Log.WriteLog("IOHelper Registry OpenSubKey Key:[" + Registry.LocalMachine.ToString() + "\\" + ComKey2 + "]", LogType.Trace);
                    if (myKey2 == null)
                    {
                        Log.WriteLog("IOHelper Registry SubKey:[" + Registry.LocalMachine.ToString() + "\\" + ComKey2 + "] is not exist", LogType.Error);
                        return tempComm;
                    } 
                    foreach (string keyName in myKey2.GetSubKeyNames())
                    {
                        string keyClass = ComKey2 + "\\" + keyName + @"\#\Control";
                        RegistryKey myKey3 = Registry.LocalMachine.OpenSubKey(keyClass);

                        Log.WriteLog("IOHelper Registry OpenSubKey Key:[" + Registry.LocalMachine.ToString() + "\\" + keyClass + "]", LogType.Trace);
                        if (myKey3 == null) continue;

                        Log.WriteLog("IOHelper Registry GetValue Key:[" + Registry.LocalMachine.ToString() + "\\" + keyClass + "] Linked:\"" + myKey3.GetValue("Linked", -1).ToString() + "\"", LogType.Trace);
                        if (Convert.ToInt32(myKey3.GetValue("Linked", -1)) == -1) continue;

                        string deviceInstanceKeyName = ComKey2 + "\\" + keyName;
                        using (RegistryKey myKey4 = Registry.LocalMachine.OpenSubKey(deviceInstanceKeyName))
                        {
                            Log.WriteLog("IOHelper Registry OpenSubKey Key:[" + Registry.LocalMachine.ToString() + "\\" + deviceInstanceKeyName + "]", LogType.Trace);
                            if (myKey4 == null) continue;
                            string deviceInstanceValue = myKey4.GetValue("DeviceInstance", string.Empty).ToString();
                            Log.WriteLog("IOHelper Registry GetValue Key:[" + Registry.LocalMachine.ToString() + "\\" + keyClass + "] DeviceInstance:\"" + deviceInstanceValue.ToString() + "\"", LogType.Trace);
                            if (string.IsNullOrEmpty(deviceInstanceValue)) continue;
                            string deviceKeyName = ComKey3 + @"\" + deviceInstanceValue;

                            SerialPortEnumInfo commInfo = new SerialPortEnumInfo();
                            using (RegistryKey myKey5 = Registry.LocalMachine.OpenSubKey(deviceKeyName))
                            {
                                Log.WriteLog("IOHelper Registry OpenSubKey Key:[" + Registry.LocalMachine.ToString() + "\\" + deviceKeyName + "]", LogType.Trace);
                                if (myKey5 == null) continue;
                                commInfo.desc = myKey5.GetValue("DeviceDesc", "").ToString();
                                commInfo.FriendlyName = myKey5.GetValue("FriendlyName", "").ToString();
                                commInfo.mfg = myKey5.GetValue("Mfg", "").ToString();

                                Log.WriteLog("IOHelper Registry GetValue Key:[" + Registry.LocalMachine.ToString() + "\\" + myKey5 + "] DeviceDesc:\"" + commInfo.desc + "\"", LogType.Trace);
                                Log.WriteLog("IOHelper Registry GetValue Key:[" + Registry.LocalMachine.ToString() + "\\" + myKey5 + "] FriendlyName:\"" + commInfo.FriendlyName + "\"", LogType.Trace);
                                Log.WriteLog("IOHelper Registry GetValue Key:[" + Registry.LocalMachine.ToString() + "\\" + myKey5 + "] Mfg:\"" + commInfo.mfg + "\"", LogType.Trace);
                            }

                            string deviceParametersKeyName = deviceKeyName + @"\Device Parameters";
                            using (RegistryKey myKey6 = Registry.LocalMachine.OpenSubKey(deviceParametersKeyName))
                            {
                                Log.WriteLog("IOHelper Registry OpenSubKey Key:[" + Registry.LocalMachine.ToString() + "\\" + deviceParametersKeyName + "]", LogType.Trace);
                                if (myKey6 == null) continue;
                                string portName = myKey6.GetValue("PortName", "").ToString();
                                foreach (SerialPortEnumInfo info in tempComm)
                                {
                                    if (info.name == portName)
                                    {
                                        commInfo.name = info.name;
                                        commInfo.path = info.path;
                                        commInfo.num = info.num;
                                        commInfoList.Add(commInfo);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Log.WriteLog("IOHelper Registry operate error:" + e.Message, LogType.Error);
            }
            return commInfoList;
        }

        public string GetComByFriendlyName(string friendlyName)
        {
            //string huaWeiFriendlyName = "HUAWEI Mobile Connect - 3G PC UI Interface";
            List<SerialPortEnumInfo> commInfoList = GetCommInfoList();
            foreach (SerialPortEnumInfo commInfo in commInfoList)
            {
                if (commInfo.FriendlyName.Contains(friendlyName))
                {
                    return commInfo.name;
                }
            }
            return null;
        }

        private bool isNumber(string s)
        {
            Regex rx = new Regex("^[0-9]*$");
            return rx.IsMatch(s);
        }

        public struct SerialPortEnumInfo
        {
            public int num;   //串口号
            public string name; //串口名称
            public string FriendlyName; //友好名称
            public string path;  //设备路径
            public string desc; //描述
            public string mfg; //注释
        }
    }
}
